﻿using System;
using System.Collections.Generic;
using System.Text;

namespace CANMonitor
{

	// 1. CanMsg类的主要职责 : CanMsg的生成 与 快速比较
	// 2. CanMsg类的附加职责， 能去掉就去掉，以保持简洁
	// 3. 
	public class CanMsg :IEquatable<CanMsg>,IComparable<CanMsg>
	{
		public static UInt32 gTick; 
		//----------------------------------------------------------------------------------------

		// 【A组成员】 原始数据，一旦生成不再变化。A 被视为app接口
		public UInt64 mTick;
		public byte   mChannal;
		public UInt32 mID;	
		public byte[] mData;	// 如果没有数据时，为null

		public bool mIsTx;
		public bool mIsExt;
		public bool mIsRtr;
		public byte mDlc;


		// 【B组成员】 由 A 生成，一旦生成不再变化，实为A组数据的另一种形式。B为方便计算C组数据
		private UInt64   mMeta_ID;			// 由 A _Chann、_ID、_isTx、_isExt、_isRtr 生成
		private UInt64   mMeta_Data;		// 由 A _Data 生成
		private string   mMeta_String;		// 由 A 所有数据生成，可延时生成
		private string[] mMeta_StrArry;		// 由 A 所有数据生成，可延时生成

		// ---------------------------------------------------------------------------------------------------
		// CanMsg 的生成

		private CanMsg() { }

		public static CanMsg Parse(UInt32 tick, UInt32 id, byte[] data, bool isTx, bool isExt, bool isRtr)
		{
			CanMsg msg = new CanMsg();

			// 生成 A组数据
			CanMsg.gTick += (UInt16)(tick - CanMsg.gTick);
			msg.mTick = CanMsg.gTick;
			msg.mID = id;
			msg.mIsTx = isTx;
			msg.mIsExt = isExt;
			msg.mIsRtr = isRtr;

			msg.mData = null;
			msg.mDlc = 0;
			if(data != null)
			{
				msg.mDlc = (byte)data.Length;
				msg.mData = new byte[data.Length];
				for(int i = 0; i < data.Length; i++)
				{
					msg.mData[i] = data[i];
				}
			}


			// 生成 B组数据
			msg.mMeta_ID = ((UInt64)msg.mChannal) << 56;
			if (msg.mIsTx) msg.mMeta_ID |= ((UInt64)0x01) << 55;
			if (msg.mIsExt) msg.mMeta_ID |= ((UInt64)0x01) << 54;
			if (msg.mIsRtr) msg.mMeta_ID |= ((UInt64)0x01) << 53;
			msg.mMeta_ID |= msg.mID;

			msg.mMeta_Data = 0;
			if (msg.mData != null)
			{
				for (int i = 0; i < msg.mData.Length; i++)
				{
					msg.mMeta_Data |= ((UInt64)msg.mData[i]) << (7 - i) * 8;
				}
			}

			msg.mMeta_String = null;
			//msg._Meta_String = msg.ToString();

			return msg;
		}

		public static CanMsg Parse(UInt32 tick, UInt32 id, byte[] data)
		{
			return Parse(tick, id, data, false, false, false);
		}

		public static CanMsg Parse(string str)
		{
			try
			{
				// 解析字符串中的数据
				//时间点 + 地址 + Tx/Rx + Ext + d/r + dlc + data[]
				//4.004150 3DA rx std d 8 30 0A E6 00 00 50 00 00
				int index = 0;
				string[] strList = str.Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);

				UInt32 tick = (UInt32)(Double.Parse(strList[index++]) * 1000);
				UInt32 id = UInt32.Parse(strList[index++], System.Globalization.NumberStyles.HexNumber);

				bool isTx = (strList[index++] == "Tx");
				bool isExt = (strList[index++] == "ext");
				bool isRtr = (strList[index++] == "r");
				byte dlc = Byte.Parse(strList[index++]);

				byte[] data = new byte[dlc];
				for (int i = 0; i < dlc; i++)
				{
					data[i] = Byte.Parse(strList[index++], System.Globalization.NumberStyles.HexNumber);
				}

				// 生成CanMsg对象
				return Parse(tick, id, data, isTx, isExt, isRtr);
			}
			catch
			{
				return null;
			}
		}


		public override string ToString()
		{
			if (this.mMeta_String != null)
				return this.mMeta_String;

			//将CAN消息转换为字符串:
			//时间点 + 地址 + Tx/Rx + Ext + d/r + dlc + data[]
			//4.004150 3DA rx std d 8 30 0A E6 00 00 50 00 00
			StringBuilder result = new StringBuilder();

			result.Append(mTick.ToString("X"));
			result.Append("\t ");

			result.Append((mID & 0x1FFFFFFF).ToString("X3"));
			result.Append("  ");

			result.Append(mIsTx ? "\ttx" : "\trx");
			result.Append("  ");

			result.Append(mIsExt ? "ext" : "std");
			result.Append("  ");

			result.Append(mIsRtr ? " r" : " d");
			result.Append("  ");

			result.Append(mDlc.ToString());
			result.Append("  ");

			if (mData != null)
			{
				foreach (byte item in mData)
				{
					result.Append(item.ToString("X2"));
					result.Append(' ');
				}
			}

			this.mMeta_String = result.ToString();
			return this.mMeta_String;
		}

		public string ToShortString()
		{
			//将CAN消息转换为字符串:
			//时间点 + 地址 + Tx/Rx + Ext + d/r + dlc + data[]
			//4.004150 3DA rx std d 8 30 0A E6 00 00 50 00 00
			StringBuilder result = new StringBuilder();
			result.Append("0x");
			result.Append((mID & 0x1FFFFFFF).ToString("X8"));
			result.Append(mIsExt ? " Ext" : " Std");
			result.Append(mIsRtr ? " r " : " d ");
			result.Append(mDlc.ToString());
			if (mData != null)
			{
				foreach (byte item in mData)
				{
					result.Append(' ');
					result.Append(item.ToString("X2"));
				}
			}
			return result.ToString();
		}

		public string[] ToStringArr()
		{
			if (this.mMeta_StrArry != null) return this.mMeta_StrArry;

			//将CAN消息转换为字符串: 
			//时间点 + 地址 + Tx/Rx + Ext + d/r + dlc + data[]
			//4.004150 3DA rx std d 8 30 0A E6 00 00 50 00 00
			this.mMeta_StrArry = new string[7];

			mMeta_StrArry[0] = ((double)mTick / 1000).ToString("F3");
			mMeta_StrArry[1] = (mID & 0x1FFFFFFF).ToString("X3");
			mMeta_StrArry[2] = mIsTx ? "Tx" : "Rx";
			mMeta_StrArry[3] = mIsExt ? "ext" : "std";
			mMeta_StrArry[4] = mIsRtr ? "r" : "d";
			mMeta_StrArry[5] = mDlc.ToString();

			if (mData != null)
			{
				StringBuilder data_str = new StringBuilder();
				foreach (byte item in mData)
				{
					data_str.Append(item.ToString("X2"));
					data_str.Append(' ');
				}
				mMeta_StrArry[6] = data_str.ToString();
			}
			else
			{
				mMeta_StrArry[6] = "";
			}

			return this.mMeta_StrArry;
		}



		// ---------------------------------------------------------------------------------------------------
		// CanMsg 的比较

		public bool Equals(CanMsg other)	// IEquatable.Equals 实现
		{
			return (this.mMeta_ID != other.mMeta_ID && this.mMeta_Data != other.mMeta_Data);
		}

		public int CompareTo(CanMsg other)	//IComparable.CompareTo 实现
		{
			if (this.mMeta_ID != other.mMeta_ID)
				return this.mMeta_ID.CompareTo(other.mMeta_ID);

			return this.mMeta_Data.CompareTo(other.mMeta_Data);
		}

		// ------------------------------------------------------------------------------------------------------------
		// CANalyst-II 存储的报文格式

		//                  (Tick, 100us级)
		// 序号   系统时间     时间标识   CAN号  方向 ID号    帧类型 帧格式  长度 数据
		// [0]    [1]          [2]        [3]    [4]  [5]     [6]    [7]     [8]  [9][10]
		// 100	  17:46:15.597 0xC8D5C5   ch1    接收 0x0531  数据帧 标准帧  0x08 x| 01 00 00 00 00 00 00 00   
		static public CanMsg Parse(string msg_str, string formate)
		{
			if (formate != "CANalyst_II")
				return null;

			try
			{
				// 解析字符串中的数据
				//时间点 + 地址 + Tx/Rx + Ext + d/r + dlc + data[]
				//4.004150 3DA rx std d 8 30 0A E6 00 00 50 00 00

				string[] strList = msg_str.Split(new char[] { '\t', ' ' }, StringSplitOptions.RemoveEmptyEntries);

				string tick_str = strList[2].Substring(2, strList[2].Length - 2);
				UInt32 tick = UInt32.Parse(tick_str, System.Globalization.NumberStyles.HexNumber);

				string id_str = strList[5].Substring(2,strList[5].Length - 2);
				UInt32 id = UInt32.Parse(id_str, System.Globalization.NumberStyles.HexNumber);

				bool isTx = (strList[4] == "发送");
				bool isExt = (strList[6] == "扩展帧");
				bool isRtr = (strList[7] == "远程帧");

				string dlc_str = strList[8].Substring(2,strList[8].Length - 2);
				byte dlc = Byte.Parse(dlc_str, System.Globalization.NumberStyles.HexNumber);


				byte[] data = new byte[dlc];
				for (int i = 0; i < dlc; i++)
				{
					data[i] = Byte.Parse(strList[10 + i], System.Globalization.NumberStyles.HexNumber);
				}

				return Parse(tick, id, data, isTx, isExt, isRtr);
			}
			catch
			{
				return null;
			}
		}

	} // endof CanMsg


}